package com.chinackts.auth.service;

import com.alibaba.fastjson.JSONObject;
import com.chinackts.auth.dto.AuthInitDto;
import com.chinackts.auth.dto.LoginParamsDto;
import com.chinackts.auth.exception.AuthInitException;
import com.chinackts.auth.model.CookieStore;
import com.chinackts.auth.repository.redis.CookieStoreRepository;
import com.chinackts.auth.repository.redis.ICCardRepository;
import com.chinackts.auth.repository.redis.LoginParamsRepository;
import com.chinackts.auth.repository.redis.SocialCreditCodeRepository;
import com.chinackts.common.exception.ApplicationException;
import com.chinackts.common.idgen.SecureRandomIdentifierGenerator;
import com.chinackts.common.okhttp.OkHttpProxySelector;
import com.chinackts.common.okhttp.OkHttpRequest;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Lianhong
 * @since 2021/10/25
 */
@Service
@Slf4j
public class AuthService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthService.class);
//
//    private static final String[] FIELDS = {
//            "dominate",
//            "t1",
//            "tps",
//            "sgm",
//            "random",
//            "serverDate",
//            "lt",
//            "execution",
//            "swLoginFlag",
//            "lpid",
//            "_eventId",
//            "devType",
//            "raCode"
//    };
//
//    //    private static final String LOGIN_URL = "https://app.singlewindow.cn/cas/login?service=https://i.chinaport.gov.cn/deskserver/j_spring_cas_security_check";
//    private static final String LOGIN_URL = "https://app.singlewindow.cn/cas/login?_loginCportCU=1&service=https://www.chinaport.gov.cn/center/userinfodemo/userinfo";


    private static final String[] FIELDS = {"random", "serverDate", "lt", "execution", "swLoginFlag", "lpid", "_eventId"};

    //    private static final String LOGIN_URL = "https://app.singlewindow.cn/cas/login?service=https://i.chinaport.gov.cn/deskserver/j_spring_cas_security_check";
    private static final String LOGIN_URL = "https://app.singlewindow.cn/cas/login?_local_card_flag=1";

    @Resource(name = "proxyOkHttpRequest")
    private OkHttpRequest request;
    @Resource
    private LoginParamsRepository loginParamsRepository;
    @Resource
    private CookieStoreRepository cookieStoreRepository;
    @Resource
    private SocialCreditCodeRepository socialCreditCodeRepository;
    @Resource
    private ICCardRepository icCardRepository;
    @Resource
    private OkHttpClient okHttpClient;
    @Resource
    private OkHttpProxySelector okHttpProxySelector;

    @Retryable(value = AuthInitException.class)
    public AuthInitDto init() {
        String id = SecureRandomIdentifierGenerator.gen();
        //访问登录，获取登录所需参数
        String loginHtml;
        List<CookieStore> cookies = new ArrayList<>();
        Request request = new Request.Builder().url(LOGIN_URL).build();
        OkHttpClient client = okHttpClient.newBuilder()
                .proxySelector(okHttpProxySelector)
                .cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
                        if (CollectionUtils.isEmpty(list)) return;
                        list.forEach(c -> {
                            CookieStore storage = new CookieStore();
                            storage.convert(c);
                            cookies.add(storage);
                        });
                    }

                    @Override
                    public List<Cookie> loadForRequest(HttpUrl httpUrl) {
                        return Collections.emptyList();
                    }
                }).build();
        //访问登录，获取登录所需参数
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful() || response.body() == null) {
                throw new AuthInitException("电子口岸初始化错误，请重试。");
            }
            loginHtml = response.body().string();
        } catch (Exception e) {
            log.error("登录初始化异常", e);
            throw new AuthInitException("电子口岸初始化错误，请重试。");
        }
//        Document doc = Jsoup.parse(loginHtml);
//        Element loginInfo = doc.getElementById("fm1");
//        JSONObject loginParams = new JSONObject();
//        for (String field : FIELDS) {
////            String value = this.loginHtmlValue(loginHtml, " name=\"" + field + "\" value=\"(.*?)\"");
//            Element item = loginInfo.getElementById(field);
//            if (item == null) {
//                Elements items = loginInfo.getElementsByAttributeValue("name", field);
//                item = items != null ? items.get(0) : null;
//            }
//            if (item == null) continue;
//            loginParams.put(field, item.val());
//        }

        JSONObject loginParams = new JSONObject();
        for (String field : FIELDS) {
            String value = this.loginHtmlValue(loginHtml, " name=\"" + field + "\" value=\"(.*?)\"");
            loginParams.put(field, value);
        }
        String random = loginParams.getString("random");
        String lt = loginParams.getString("lt");
        String _eventId = loginParams.getString("_eventId");
        if (StringUtils.isAnyBlank(random, lt, _eventId)) {
            LOGGER.error("电子口岸初始化异常,randoms、lts或_eventIds为null。");
            throw new AuthInitException("电子口岸初始化异常，randoms、lts或_eventIds获取失败。");
        }
        //缓存初始化访问获取的cookies
        cookieStoreRepository.saveCookies(id, cookies);
        cookieStoreRepository.expire(id);
        //缓存登录参数
        loginParamsRepository.saveLoginParams(id, loginParams);
        AuthInitDto dto = new AuthInitDto();
        dto.setId(id);
        dto.setRandom(random);
        return dto;
    }

    private String loginHtmlValue(String value, String regx) {
        Pattern pattern = Pattern.compile(regx);// 匹配的模式
        Matcher m = pattern.matcher(value);
        while (m.find()) {
            return m.group(1);
        }
        return StringUtils.EMPTY;
    }

    public void login(String id, LoginParamsDto loginParamsDto) {
        try {
            String info = loginParamsDto.getInfo();
            JSONObject loginParams = loginParamsRepository.getLoginParams(id);
            String[] infoArr = info.split("\\|\\|");
            if (infoArr.length < 5) {
                throw new ApplicationException("9999", "请提供正确的卡信息（info）");
            }
            loginParams.put("userPin", loginParamsDto.getPassword());
            loginParams.put("signData", loginParamsDto.getSign());
            loginParams.put("certNo", infoArr[0]);
            loginParams.put("icCard", infoArr[5]);
            String loginResp = request.post(LOGIN_URL, loginParams);
            LOGGER.info("登录结果{}: {}", id, loginResp);

            List<CookieStore> cookies = cookieStoreRepository.getCookies(id);
            if (!CollectionUtils.isEmpty(cookies)) {
                for (CookieStore cookie : cookies) {
                    LOGGER.info("登录后，cookie name = " + cookie.getName() + ", cookie value = " + cookie.getValue());
                }
            }

            //清除当前登录用户之前的登录信息，仅缓存最新的用户登录信息
            icCardRepository.removeAllByIcCard(id, infoArr[5]);

            //卡信息,根据||分割后，第5位为口岸卡卡号
            icCardRepository.saveIcCard(id, infoArr[5]);

            //卡信息,根据||分割后，第8位为企业组织机构代码（企业社会信用代码第 9 至 17 位）
            socialCreditCodeRepository.saveSocialCreditCode(id, infoArr[8]);

            LOGGER.info("电子口岸登录成功！！！");
        } catch (Exception e) {
            LOGGER.error("验签登录单一窗口系统异常。", e);
            throw new RuntimeException(String.format("验签登录电子口岸系统异常：%s", e.getMessage()));
        } finally {
            //设置cookie失效时间
            cookieStoreRepository.expire(id);
        }
    }
}

